# coding: utf-8
import json

from sqlalchemy import Column, DateTime, String, Integer, Boolean, ForeignKey
from sqlalchemy.orm import relationship, backref

from flow_alchemy.core.settings import id_worker, join_path, LOG_DIR
from flow_alchemy.db import Base
from flow_alchemy.db.mixins import ModelMixin, MarkMixin
from flow_alchemy.db.work_status import ProcessStatus, UserAction, TaskStatus
from flow_alchemy.util import local_time

metadata = Base.metadata


class User(Base, ModelMixin):
    __tablename__ = 'user'

    uid = Column(Integer, nullable=False, primary_key=True)
    account = Column(String(14), unique=True, nullable=False)
    name = Column(String(14), nullable=False, unique=True)
    password = Column(String(128), nullable=False)

    enabled = Column(Boolean, default=True)
    create_date = Column(DateTime, nullable=False, default=local_time)
    update_date = Column(DateTime, nullable=False, default=local_time, onupdate=local_time)


class Role(Base, ModelMixin):
    __tablename__ = 'role'

    rid = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(14), nullable=False, default='Unname')

    enabled = Column(Boolean, default=True)
    create_date = Column(DateTime, nullable=False, default=local_time)
    update_date = Column(DateTime, nullable=False, default=local_time, onupdate=local_time)


class RoleMap(Base, ModelMixin):
    __tablename__ = 'role_map'
    id = Column(Integer, primary_key=True, autoincrement=True)
    rid = Column(Integer, ForeignKey('role.rid'))
    uid = Column(Integer, ForeignKey('user.uid'))

    enabled = Column(Boolean, default=True)
    create_date = Column(DateTime, nullable=False, default=local_time)
    update_date = Column(DateTime, nullable=False, default=local_time, onupdate=local_time)
    user = relationship('User', backref=backref('role_maps'), uselist=False, foreign_keys=[uid])
    role = relationship('Role', backref=backref('role_maps'), uselist=False, foreign_keys=[rid])


class Task(Base, ModelMixin):
    __tablename__ = 'task'
    tid = Column(Integer, primary_key=True, autoincrement=True, comment='任务号', default=id_worker.get_id)
    uid = Column(Integer, ForeignKey('user.uid'), default=0, comment='创建人id', nullable=False)
    fid = Column(Integer, ForeignKey('workflow.fid'), default=0, nullable=False)
    status = Column(Integer, default=TaskStatus.init, nullable=False)
    level = Column(Integer, default=0, nullable=False)
    create_date = Column(DateTime, nullable=False, default=local_time)
    update_date = Column(DateTime, nullable=False, default=local_time, onupdate=local_time)
    complete_date = Column(DateTime, nullable=True, default=None)
    user = relationship('User', backref=backref('task_list'), uselist=False, foreign_keys=[uid])
    flow = relationship('WorkFlow', backref=backref('task_list'), uselist=False, foreign_keys=[fid])
    # Effective date
    # Expiration date


class TaskLog(Base, ModelMixin):
    __tablename__ = 'task_log'
    id = Column(Integer, primary_key=True, autoincrement=True)
    tid = Column(Integer, ForeignKey('task.tid'), nullable=False)
    fid = Column(Integer, ForeignKey('workflow.fid'), default=0, nullable=True)
    create_date = Column(DateTime, nullable=True)
    directory = Column(String(14), nullable=True, default='')

    task = relationship('Task', backref=backref('task_log'), uselist=False, foreign_keys=[tid])
    flow = relationship('WorkFlow', backref=backref('task_log'), uselist=False, foreign_keys=[fid])

    def abs_path(self):
        return join_path(LOG_DIR, str(self.tid) + '@' + self.create_date.strftime('%Y-%m-%d %H-%M-%S') + '.json')

    def get_data(self):
        with open(self.abs_path(), 'r') as f:
            data = json.load(f)

        return data


class Process(Base, ModelMixin):
    __tablename__ = 'process'
    id = Column(Integer, primary_key=True, autoincrement=True)
    pid = Column(Integer, default=0)
    ppid = Column(Integer, default=0, comment='parent pid')
    tid = Column(Integer, ForeignKey('task.tid'))
    nid = Column(Integer, ForeignKey('node.nid'))
    uid = Column(Integer, ForeignKey('user.uid'))
    rid = Column(Integer, ForeignKey('role.rid'))
    fid = Column(Integer, ForeignKey('workflow.fid'))

    action = Column(Integer, default=UserAction.init, comment='user action result')
    status = Column(Integer, default=ProcessStatus.init, comment='flow status')
    active = Column(Boolean, default=True, comment='erp active')
    level = Column(Integer, default=0, comment='处理优先级')
    create_date = Column(DateTime, nullable=False, default=local_time)
    update_date = Column(DateTime, nullable=False, default=local_time, onupdate=local_time)

    task = relationship('Task', backref=backref('process_list'), uselist=False, foreign_keys=[tid])
    node = relationship('Node', backref=backref('process_list'), uselist=False, foreign_keys=[nid])
    user = relationship('User', backref=backref('process_list'), uselist=False, foreign_keys=[uid])
    role = relationship('Role', backref=backref('process_list'), uselist=False, foreign_keys=[rid])
    flow = relationship('WorkFlow', backref=backref('process_list'), uselist=False, foreign_keys=[fid])


class WorkFlow(Base, ModelMixin):
    __tablename__ = 'workflow'
    fid = Column(Integer, primary_key=True, )
    name = Column(String(255))
    category = Column(String(32))
    work_tables = Column(String(255))
    doc = Column(String(255), default='', nullable=False)
    enabled = Column(Boolean, default=True)
    create_date = Column(DateTime, default=local_time)


class Node(Base, ModelMixin):
    __tablename__ = 'node'
    nid = Column(Integer, primary_key=True, nullable=False)
    fid = Column(Integer, ForeignKey('workflow.fid'))
    name = Column(String(255), default='', nullable=False)
    doc = Column(String(255), default='', nullable=False)
    node_type = Column(String(255), default='', comment='base class name')
    form_path = Column(String(255), default='', nullable=False)
    form_class_name = Column(String(255), default='', nullable=False)
    has_user = Column(Boolean, default=False)
    has_role = Column(Boolean, default=False)
    has_submit = Column(Boolean, default=False)
    has_save = Column(Boolean, default=False)
    has_pass = Column(Boolean, default=True)
    has_reject = Column(Boolean, default=False)
    has_return = Column(Boolean, default=False)
    has_void = Column(Boolean, default=False)
    enabled = Column(Boolean, default=True)
    create_date = Column(DateTime, default=local_time)
    flow = relationship('WorkFlow', backref=backref('nodes'), uselist=False, foreign_keys=[fid])


class NodeConfig(Base, ModelMixin):
    __tablename__ = 'node_config'
    id = Column(Integer, primary_key=True, autoincrement=True)
    nid = Column(Integer, ForeignKey('node.nid'))
    uid = Column(Integer, ForeignKey('user.uid'), default=0)
    rid = Column(Integer, ForeignKey('role.rid'), default=0)
    fid = Column(Integer)
    enabled = Column(Boolean, default=True)

    create_uid = Column(Integer, ForeignKey('user.uid'), default=0)
    create_date = Column(DateTime, default=local_time)
    node = relationship('Node', backref=backref('configs'), uselist=False, foreign_keys=[nid])
    user = relationship('User', backref=backref('node_configs'), uselist=False, foreign_keys=[uid])
    role = relationship('Role', backref=backref('node_configs'), uselist=False, foreign_keys=[rid])
    create_user = relationship('User', backref=backref('create_node_configs'), uselist=False, foreign_keys=[create_uid])


class Edge(Base, ModelMixin):
    __tablename__ = 'edge'
    id = Column(Integer, primary_key=True, autoincrement=True)
    parent_id = Column(Integer, ForeignKey('node.nid'))
    child_id = Column(Integer, ForeignKey('node.nid'))
    fid = Column(Integer)
    name = Column(String(255), default='', nullable=False)
    doc = Column(String(255), default='', nullable=False)
    enabled = Column(Boolean, default=True)
    create_uid = Column(Integer, ForeignKey('user.uid'))
    create_date = Column(DateTime, default=local_time)
    parent = relationship('Node', backref=backref('out_edges'), uselist=False, foreign_keys=[parent_id])
    child = relationship('Node', backref=backref('in_edges'), uselist=False, foreign_keys=[child_id])
    create_user = relationship('User', backref=backref('create_edges'), uselist=False, foreign_keys=[create_uid])


class PR(Base, ModelMixin, MarkMixin):
    __tablename__ = 'example_pr'
    tid = Column(Integer, primary_key=True, nullable=False, comment='task id')
    pr_no = Column(String(36), default='', nullable=False, comment='pr no')
    budget = Column(String(36), default='', nullable=False, comment='预算')
    name = Column(String(36), default='', nullable=False, comment='商品名称')
    price = Column(Integer, nullable=False, comment='价格')
    count = Column(Integer, nullable=False, comment='数量')
    total = Column(Integer, default=0, nullable=False, comment='总金额')
    currency = Column(String(20), default='RMB', nullable=False, comment='币种')
    create_date = Column(DateTime, nullable=False, default=local_time)
    update_date = Column(DateTime, nullable=False, default=local_time, onupdate=local_time)
    mark = Column(String(32), default='', nullable=False)

    # def __init__(self, *args, **kwargs):
    #     super(PR, self).__init__(*args, **kwargs)
    #     if not self.check_mark():
    #         raise Exception('data tampered:\n'+str(self))


model_map = {PR.__name__: PR}
